<template>
  <el-form
    v-if="showForm"
    v-loading="loading"
    :element-loading-spinner="loadingSpinner"
    element-loading-svg-view-box="0,0, 1024, 1024"
    element-loading-text="正在拉取表单..."
    ref="TrendsFormRef"
    label-width="120px"
    class="form-box form-label-120 custom-loading"
    :model="formData"
    status-icon
  >
    <Content
      v-for="item in formList.filter(it => !getInfo(it)?.hidden)"
      :key="getForKey(item)"
      :formInfo="item"
      :formData="formData"
      :imgListMap="imgListMap"
      :TrendsFormRef="TrendsFormRef"
      :topExpose="topExpose"
      v-bind="$attrs"
    />
  </el-form>
</template>

<script setup>
import {
  getForKey,
  getInfo,
  isArray,
  validUploadData,
  getAllFields
} from './const';
import { getDynamicForm, getPlatformDynamicForm } from '@/api/dynamic-form';
import Content from './Content';
import { loadingSpinner } from '@/assets/js/loadingIcon.js';

const props = defineProps({
  form_uni_key: {
    type: String,
    default: '' // application_resource || batch_application_resource
  },
  form_role: {
    type: String,
    default: 'company' // company || platform
  },
  api: {
    type: Function,
    default: null // 自定义接口
  },
  params: {
    type: Object,
    default: null // 自定义参数
  },
  events: {
    type: Object,
    default: null // 自定义事件
  }
});

const emits = defineEmits();

const loading = ref(false); // 加载
const imgListMap = ref({}); // 图片上传特殊映射
const tableValidList = ref([]); // 表格校验映射
const formList = ref([]); // 接口返回的动态表单items
const formRes = ref({}); // 接口返回的动态表单最外层
const formData = ref({}); // 表单输入绑定的值

// 获取动态表单
const showForm = ref(true);
const api = computed(
  () =>
    props.api ||
    {
      company: getDynamicForm,
      platform: getPlatformDynamicForm
    }[props.form_role]
);
async function initFormList() {
  try {
    loading.value = true;
    const res = await api.value(
      props.params || {
        form_uni_key: props.form_uni_key || formRes.value.form_uni_key,
        values: initValues()
      }
    );
    formRes.value = res.data?.form || res.data || {};
    formList.value = formRes.value?.items || [];
    initFormData(formList.value);
    showForm.value = false;
    nextTick(() => {
      showForm.value = true;
    });
  } finally {
    loading.value = false;
  }
}

// 将填写的值处理成后端需要的对象数组
function initValues() {
  const values = [];
  deepList(JSON.parse(JSON.stringify(formList.value)), values);
  return values;
}

// 递归所有字段赋值给新的对象
function deepList(list, values) {
  list.forEach(item => {
    // 只处理字段类型
    if (item.level === 'form-item') {
      const _info = getInfo(item);
      const field = _info.field; // 字段名
      const _formData = JSON.parse(JSON.stringify(formData.value));
      const value = _formData[field]; // 字段值
      const passValues = ['', null, undefined]; // 直接过滤掉的值
      let addFlag = false; // 是否可添加该值
      if (_info.field_type === 'table' && !_info.is_cleared) {
        // 表格，特殊情况
        const tableInfo = tableValidList.value.find(
          item => item.field === field
        );
        if (!tableInfo) return;
        const _field_value = [];
        const _tableData = tableInfo.tableData || [];
        const _tableChildren = tableInfo.tableChildren || [];
        _tableData.forEach((row, index) => {
          if (!_field_value[index]) _field_value[index] = [];
          _tableChildren.forEach(children => {
            const rowField = children?.info?.field;
            const code = rowField.split('.')[1];
            if (row?.is_cleareds?.includes(code)) return;
            _field_value[index].push({
              field: rowField,
              field_value: getTypeValue(children?.info, row[code]),
              field_value_type: children?.info?.field_value_type
            });
          });
        });
        values.push({
          field,
          field_value: getTypeValue(_info, _field_value),
          field_value_type: _info.field_value_type
        });
      } else if (isArray(value)) {
        // 如果是数组，则需要过滤掉每一项
        for (let i = value.length - 1; i >= 0; i--) {
          const arrVal = value[i];
          if (passValues.includes(arrVal)) value.splice(i, 1);
        }
        addFlag = true;
      } else if (!passValues.includes(value)) {
        // 否则只过滤当前值
        addFlag = true;
      }
      // 赋值
      if (addFlag && !_info.is_cleared) {
        values.push({
          field,
          field_value: getTypeValue(_info, value),
          field_value_type: _info.field_value_type
        });
      }
    }
    // 递归
    if (item.children?.length) deepList(item.children, values);
  });
}

function getTypeValue(info, value) {
  if (info?.field_value_type === 'int' && value != null && value !== '') {
    if ([null, undefined, ''].includes(value)) return undefined;
    else return Number(value);
  } else if (info?.field_value_type === 'string') {
    if ([null, undefined, ''].includes(value)) return value;
    return String(value);
  } else {
    return value;
  }
}

// 将默认值赋给formData
function initFormData(list) {
  list.forEach(item => {
    const field = getInfo(item).field; // 字段名
    let defaultValue = getInfo(item).value ?? undefined; // 默认值
    if (defaultValue === '') defaultValue = undefined;
    const oldValue = formData.value[field];
    formData.value[field] = oldValue ?? defaultValue;
    // 递归
    if (item.children?.length) initFormData(item.children);
  });
}

const TrendsFormRef = ref();
async function returnData() {
  return new Promise(async (resolve, reject) => {
    if (loading.value) {
      reject();
      $msg.warning('正在加载表单，请稍等');
      return;
    }

    try {
      // 表格校验
      const allFields = [];
      getAllFields(formList.value, allFields);
      await Promise.all(
        tableValidList.value
          ?.filter(item => allFields.includes(item?.field))
          .map(item => item?.validFn?.())
      );
      await TrendsFormRef.value.validate();
      //校验上传
      if (!validUploadData(imgListMap.value, formList.value)) return reject();
      resolve(initValues());
    } catch {
      reject();
      $msg.warning('表单校验不通过，请检查');
    }
  });
}

// 需要传递下去的常量或方法
const topExpose = computed(() => {
  return {
    form_uni_key: props.form_uni_key || formRes.value.form_uni_key,
    form_role: props.form_role,
    events: props.events,
    initValues,
    initFormList,
    tableValidList,
    formList
  };
});

defineExpose({ initFormList, returnData });
</script>

<style lang="scss" scoped>
.form-box {
  min-height: 200px;
}
</style>
